package com.dwy2002.product.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dwy2002.common.Result;
import com.dwy2002.common.exception.EmptyIdException;
import com.dwy2002.common.utils.OssUtils;
import com.dwy2002.common.utils.Validator;
import com.dwy2002.enums.NumberEnum;
import com.dwy2002.enums.Status;
import com.dwy2002.pojo.dto.product.ProductPageDTO;
import com.dwy2002.pojo.dto.product.ProductsDTO;
import com.dwy2002.pojo.dto.product.ProductsImagesDTO;
import com.dwy2002.pojo.dto.users.ProductFavoritesPageDTO;
import com.dwy2002.pojo.po.product.ProductCategory;
import com.dwy2002.pojo.po.product.ProductImages;
import com.dwy2002.pojo.po.product.Products;
import com.dwy2002.pojo.vo.product.ProductDetailVO;
import com.dwy2002.pojo.vo.product.ProductImagesVO;
import com.dwy2002.pojo.vo.product.ProductReviewsVO;
import com.dwy2002.product.mapper.ProductCategoryMapper;
import com.dwy2002.product.mapper.ProductImagesMapper;
import com.dwy2002.product.mapper.ProductsMapper;
import com.dwy2002.product.service.IProductCategoryService;
import com.dwy2002.product.service.IProductImagesService;
import com.dwy2002.product.service.IProductReviewsService;
import com.dwy2002.product.service.IProductsService;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Objects;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;

import static com.dwy2002.common.Result.*;
import static com.dwy2002.common.utils.Utils.*;
import static com.dwy2002.enums.rabbit.FavoritesRabbitConstants.FAVORITES_REQUEST_EXCHANGE;
import static com.dwy2002.enums.rabbit.FavoritesRabbitConstants.FAVORITES_REQUEST_ROUTING_KEY;

/**
 * @author 杜伟毅
 * @version 1.0
 * @since 2025/02/17
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ProductsServiceImpl extends ServiceImpl<ProductsMapper, Products> implements IProductsService {
    /**
     * 自定义线程池（单例）
     */
    private static final Executor CUSTOM_EXECUTOR = Executors.newFixedThreadPool(
            10,  // 核心线程数（根据业务需求调整）
            new ThreadFactory() {
                private final AtomicInteger counter = new AtomicInteger(1);

                @Override
                public Thread newThread(@NonNull Runnable r) {
                    return new Thread(r, "product-pool-" + counter.getAndIncrement());
                }
            }
    );
    private final OssUtils ossUtils;
    private final IProductCategoryService productCategoryService;
    private final IProductImagesService imagesService;
    private final ProductImagesMapper productImageMapper;
    private final IProductReviewsService productReviewsService;
    private final RabbitTemplate rabbitTemplate;
    private final RedisTemplate<String, Object> redisTemplate;
    private final ProductCategoryMapper categoryMapper;
    private final ReentrantLock lock = new ReentrantLock();

    /**
     * 添加商品
     *
     * @param products 接收前端的商品数据
     * @author 杜伟毅
     * @since 2025/2/18 0018 21:29
     */
    @Override
    public Result<Void> saveProduct(ProductsDTO products) {
        Validator.of(products)
                .notEmpty(ProductsDTO::getTitle, "商品标题不能为空")
                .notEmpty(ProductsDTO::getSpecification, "商品规格不能为空")
                .notEmpty(ProductsDTO::getUnit, "计量单位不能为空")
                .notZeroDecimal(ProductsDTO::getPrice, "价格不能为空")
                .notNull(ProductsDTO::getQuantity, "商品数量不能为空")
                .inRange(ProductsDTO::getQuantity, 99999, 0, "商品数量不能低于0或高于99999")
                .notEmpty(ProductsDTO::getCategoriesId, "分类选项不能为空")
                .validate();
        // 生成商品ID
        String productId = IdWorker.get32UUID();

        Products product = BeanUtil.copyProperties(products, Products.class);
        product.setId(productId);
        boolean save = save(product);

        //保存图片
        saveProductImage(products.getImages(), productId);

        //保存商品与分类之间的关系
        Boolean PCsaved = productCategoryService.saveProductToCategory(productId, products.getCategoriesId());

        return handleResult(save || PCsaved, "商品添加成功", "商品添加失败");
    }

    /**
     * 删除商品（支持单个删除和批量删除）
     *
     * @param ids 商品id集合
     * @author 杜伟毅
     * @since 2025/2/19 0019 23:43
     */
    @Override
    public Result<Void> deleteListProduct(List<String> ids) {
        if (isListEmpty(ids)) return fail(Status.BAD_REQUEST, "id不能为空");

        //删除封面图片
        LambdaQueryWrapper<Products> lqw = new LambdaQueryWrapper<>();
        lqw.in(Products::getId, ids);
        List<String> productIds = list(lqw).stream()
                .filter(Objects::nonNull)
                .map(Products::getId)
                .toList();

        // 批量删除商品图片
        imagesService.deleteBathImage(productIds);

        //删除商品与分类关系
        productCategoryService.deleteProductCategoryByProductId(productIds);

        //删除商品评论
        productReviewsService.deleteReviews(productIds);

        //删除收藏商品数据
        sendCancelFavoritesRequest(productIds);

        boolean remove = removeByIds(productIds);
        return handleResult(remove, "删除成功", "删除失败");
    }

    /**
     * 分页查询
     * <p>
     * 查询：可按标题搜索
     * <p>
     * 排序：可按商品规格、商品创建时间、商品修改时间、商品数量、商品价格进行升序和降序排序
     * <p>
     * 分类：可按是否售罄、计量单位进行分类。
     *
     * @param dto 商品分页数据
     * @author 杜伟毅
     * @since 2025/2/23 0023 21:24
     */
    @Override
    public Result<Page<Products>> getProductPage(ProductPageDTO dto) {
        Validator.of(dto)
                .mustSatisfy(isPageNull(dto.getPageNo(), dto.getPageSize()), "请传入分页数据")
                .mustSatisfy(isPageZero(dto.getPageNo(), dto.getPageSize()), "分页数据不能为0")
                .validate();

        Page<Products> page = new Page<>(dto.getPageNo(), dto.getPageSize());
        return success(this.baseMapper.selectProductPage(page, dto));
    }

    /**
     * 获取商品详情
     *
     * @param id 商品id
     * @author 杜伟毅
     * @since 2025/2/27 0027 10:02
     */
    @Override
    public Result<ProductDetailVO> getProductDetail(String id) throws ExecutionException, InterruptedException {
        if (isEmptyOrNull(id)) {
            return fail(Status.BAD_REQUEST, "id不能为空");
        }
        Products products = getById(id);

        if (ObjectUtils.isEmpty(products)) {
            return fail(Status.BAD_REQUEST, "没有这个商品");
        }
        ProductDetailVO productDetail = BeanUtil.copyProperties(products, ProductDetailVO.class);

        // 2. 并行查询图片和评价
        CompletableFuture<List<ProductImages>> imagesFuture = CompletableFuture.supplyAsync(() -> {
            LambdaQueryWrapper<ProductImages> query = new LambdaQueryWrapper<>();
            query.eq(ProductImages::getProductId, id);
            return productImageMapper.selectList(query);
        }, CUSTOM_EXECUTOR); // 关键点：传入自定义线程池

        CompletableFuture<List<ProductReviewsVO>> reviewsFuture = CompletableFuture.supplyAsync(() ->
                productReviewsService.getProductReviews(id), CUSTOM_EXECUTOR); // 关键点：传入自定义线程池

        // 3. 等待并组装结果
        productDetail.setImages(BeanUtil.copyToList(imagesFuture.get(), ProductImagesVO.class));
        productDetail.setReviews(reviewsFuture.get());
        productDetail.setCategoriesId(categoryMapper.selectOne(new LambdaQueryWrapper<ProductCategory>().eq(ProductCategory::getProductId, id)).getCategoryId());
        return success(productDetail);
    }

    /**
     * 修改商品
     *
     * @param dto 接收前端的商品数据
     * @author 杜伟毅
     * @since 2025/2/19 0019 15:54
     */
    @Override
    public Result<Void> updateProduct(ProductsDTO dto) {
        Validator.of(dto)
                .notEmpty(ProductsDTO::getTitle, "商品标题不能为空")
                .notEmpty(ProductsDTO::getSpecification, "商品规格不能为空")
                .notEmpty(ProductsDTO::getUnit, "计量单位不能为空")
                .notZeroDecimal(ProductsDTO::getPrice, "价格不能为空")
                .notNull(ProductsDTO::getQuantity, "商品数量不能为空")
                .inRange(ProductsDTO::getQuantity, 99999, 0, "商品数量不能低于0或高于99999")
                .notEmpty(ProductsDTO::getCategoriesId, "分类选项不能为空")
                .validate();

        Products product = getById(dto.getId());
        if (ObjectUtils.isEmpty(product)) return fail(Status.BAD_REQUEST, "商品不存在");

        LambdaUpdateWrapper<Products> luw = new LambdaUpdateWrapper<>();
        luw.eq(Products::getId, dto.getId())
                .set(Products::getTitle, dto.getTitle())
                .set(!isEmptyOrNull(dto.getDescription()), Products::getDescription, dto.getDescription())
                .set(!isEmptyOrNull(dto.getSpecification()), Products::getSpecification, dto.getSpecification())
                .set(!isEmptyOrNull(dto.getUnit()), Products::getUnit, dto.getUnit())
                .set(Objects.nonNull(dto.getPrice()), Products::getPrice, dto.getPrice())
                .set(Objects.nonNull(dto.getQuantity()), Products::getQuantity, dto.getQuantity())
                .set(!isEmptyOrNull(dto.getImage()), Products::getImage, dto.getImage());

        boolean update = update(luw);

        //保存图片
        saveProductImage(dto.getImages(), dto.getId());

        // 更安全的删除旧封面图片逻辑
        if (!StringUtils.equals(product.getImage(), dto.getImage())
                && !StringUtils.isEmpty(product.getImage())) {
            try {
                // 确认新图片已存在再删除旧图片
                if (ossUtils.isImageExist(dto.getImage())) {
                    ossUtils.deleteImage(product.getImage());
                }
            } catch (Exception e) {
                log.error("删除旧封面图片失败: {}", product.getImage(), e);
            }
        }


        return handleResult(update, "商品修改成功", "商品修改失败");
    }

    /**
     * 下架商品
     *
     * @param id 商品id
     * @author 杜伟毅
     * @since 2025/3/2 0002 11:08
     */
    @Override
    public Result<Void> takeOffProduct(String id) {
        if (isEmptyOrNull(id)) return fail(Status.BAD_REQUEST, "id不能为空");
        LambdaUpdateWrapper<Products> luw = new LambdaUpdateWrapper<>();
        luw.eq(Products::getId, id)
                .set(Products::getIsOffShelf, NumberEnum.ONE.getValue());
        return handleResult(update(luw), "下架成功", "下架失败");
    }

    /**
     * 上架商品
     *
     * @param id 商品id
     * @author 杜伟毅
     * @since 2025/3/2 0002 15:07
     */
    @Override
    public Result<Void> listProduct(String id) {
        if (isEmptyOrNull(id)) return fail(Status.BAD_REQUEST, "id不能为空");
        LambdaUpdateWrapper<Products> luw = new LambdaUpdateWrapper<>();
        luw.eq(Products::getId, id)
                .set(Products::getIsOffShelf, NumberEnum.ZERO.getValue());
        return handleResult(update(luw), "上架成功", "上架失败");
    }

    /**
     * 扣减商品
     *
     * @param productId 商品id
     * @param quantity  购买数量
     * @author 杜伟毅
     * @since 2025/3/10 0010 22:37
     */
    @Override
    public void deductionProduct(String productId, Integer quantity) {
        if (isEmptyOrNull(productId)) throw new EmptyIdException("deductionProduct");
        //查看商品库存
        Products product = getById(productId);
        if (product == null) return;
        //进行扣减
        lock.lock();
        try {
            LambdaUpdateWrapper<Products> luw = new LambdaUpdateWrapper<>();
            luw.eq(Products::getId, productId)
                    .setDecrBy(isValidInventoryForDeduction(product.getQuantity(), quantity), Products::getQuantity, quantity);
            update(luw);
        } finally {
            lock.unlock();
        }

    }

    /**
     * 根据id集合查询商品
     *
     * @param productIds 商品id集合
     * @param dto        商品收藏DTO
     * @author 杜伟毅
     * @since 2025/3/25 0025 23:55
     */
    @Override
    public List<Products> queryProductsWithDynamicConditions(List<String> productIds, ProductFavoritesPageDTO dto) {
        LambdaQueryWrapper<Products> lqw = new LambdaQueryWrapper<Products>()
                .in(Products::getId, productIds)
                .like(!isEmptyOrNull(dto.getTitle()), Products::getTitle, dto.getTitle())
                .orderBy(dto.getCreatedEnabled(), dto.getCreatedIsAsc(), Products::getCreatedAt)
                .orderBy(dto.getUpdatedEnabled(), dto.getUpdatedIsAsc(), Products::getUpdatedAt);
        return list(lqw);
    }

    /**
     * 获取商品单位
     *
     * @author 杜伟毅
     * @since 2025/5/9 0009 17:25
     */
    @Override
    public Result<List<String>> getProductUnit() {
        return success(list(new LambdaQueryWrapper<Products>().select(Products::getUnit).groupBy(Products::getUnit)).stream().map(Products::getUnit).toList());
    }


    //----------------------------------------------------------------------------------

    /**
     * 验证商品数量是否小于0或小于扣减的数
     *
     * @param quantity         库存
     * @param quantityToDeduct 购买数量
     * @return true：条件符合 false：条件不符合
     * @author 杜伟毅
     * @since 2025/3/10 0010 23:55
     */
    private boolean isValidInventoryForDeduction(int quantity, int quantityToDeduct) {
        return quantity >= 0 && quantity >= quantityToDeduct;
    }

    /**
     * 提取方法：保存方法
     *
     * @param images    商品图片集合
     * @param productId 商品id
     * @author 杜伟毅
     * @since 2025/2/24 0024 22:19
     */
    private void saveProductImage(List<ProductsImagesDTO> images, String productId) {
        for (ProductsImagesDTO image : images) {
            image.setProductId(productId);
            if (!imagesService.saveProductImage(image)) {
                continue;
            }
        }
    }

    /**
     * 子方法：发送商品id集合
     *
     * @param productIds 商品id集合
     * @author 杜伟毅
     * @since 2025/3/25 0025 18:04
     */
    public void sendCancelFavoritesRequest(List<String> productIds) {
        rabbitTemplate.convertAndSend(
                FAVORITES_REQUEST_EXCHANGE,
                FAVORITES_REQUEST_ROUTING_KEY,
                productIds
        );
    }
}
